#ifndef THREESTEPONEPASSDBOPERATIONMODEL_H_JM_20130219
#define THREESTEPONEPASSDBOPERATIONMODEL_H_JM_20130219

#include "../generators/ModelGenerator.h"
#include "../generators/Slices.h"
#include "../boxes/DefaultGroupDefinitions.h"
#include "../boxes/DbOperationVersion.h"

#include "DataInputModelPartGenerator.h"
#include "DataOutputModelPartGenerator.h"

namespace jm4bbx {

	class  ThreeStepOnePassDbOperationModel : public ModelGenerator {
	public:
		ThreeStepOnePassDbOperationModel(
			const int N, // parallelism level
			const std::string& inputBoxName,
			const InputBoxConfiguration& firstInpBoxConf,
			const InputBoxConfiguration& secondInpBoxConf,
			const std::string& hashBoxName,
			const std::string& actionBoxName,
			const std::string& outputBoxName,
			const std::string& outputForm,
			const std::string& typeName,
			const bool bagVersion,
			const std::string& resultCreatorBoxName) {

				/// Input
				DataInputModelPartGenerator inGen;
				// Naschval  v opacnom poradi pretoze modely su navrhnute 
				// na zahesovavanie prveho argumentu. Vypocet pocita 
				// s tym ze su zamenene.
				InputBoxConfiguration confs[2] = {secondInpBoxConf, firstInpBoxConf};
				inGen.addBoxes(this, inputBoxName, confs, 2, N, true, false);
				//inGen.getForkDataBox(1)->addBoxParam(genBoxParam("time_report", 1));
				///


				BoxDescriptorPtr hash = addBox(hashBoxName, 
					genBoxParam("signal_out", 1),  N);


				BoxDescriptorPtr action = addBox(actionBoxName, 
					genBoxParam("signal_out", N) + 
					genBoxParam(
					DbOperationVersion::DB_OPERATION_VERSION_PARAM_NAME, 
					bagVersion), 
					N);

				std::vector<BoxDescriptorPtr> resulters;

				for (int i = 0; i < N; ++i) {
					resulters.push_back(addBox(resultCreatorBoxName, 
						genBoxParam("signal_in", N) + 
						genBoxParam("signal_out", 1) +
						genBoxParam("parallelism", N) +
						genBoxParam("parallel_index", i) + 
						genBoxParam(DbOperationVersion::
						DB_OPERATION_VERSION_PARAM_NAME, bagVersion)
						));						
				}

				/// Output
				DataOutputModelPartGenerator oGen;
				oGen.addBoxes(this, outputBoxName, outputForm, N);

				//--------------------------------------------------------------
				//--------------------------------------------------------------
				//-------------------------------------------------------------- 
				// vstup do vypoctu


				inGen.addSlices(this, typeName);


				addSlice(new ForkSlice(inGen.getForkDataBox(0)->getBoxId(), 
					hash->getBoxIds(), N, D_O, D_I, genTypes(typeName, 1)));

				addSlice(new MergeSlice(hash->getBoxIds(), 
					inGen.getForkDataBox(1)->getBoxId(), N, S_O, S_I));

				addSlice(new ForkSlice(inGen.getForkDataBox(1)->getBoxId(), 
					action->getBoxIds(), N, D_O, D_I, genTypes(typeName, 1)));


				for (size_t i = 0; i < N; ++i) {
					addSlice(new MergeSlice(action->getBoxIds(), 
						resulters[i]->getBoxId(), N, S_O + i, S_I));

					addSlice(new PlainSlice(resulters[i]->getBoxId(), 
						oGen.getTimerReportBox()->getBoxId(), S_O, S_I + i));

					addSlice(new PlainSlice(resulters[i]->getBoxId(), 
						oGen.getOutputBoxes()->getBoxIds()[i],D_O, D_I, 
						genTypes("BinaryOperationResultIndex", 1)));	
				}

				oGen.addSlices(this);

		}
	};

} // namespace jm4bbx


#endif
